package com.xmlit.project.engine.struct.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
//import java.util.regex.Pattern;

import com.xmlit.project.engine.struct.Struct;

public abstract class StructImpl implements Struct {

	List<Struct> children = null;
	HashMap<String, Struct> childrenMap = null;
	int maxOccurrences = 1;
	int minOccurrences = 1;

	String name = null;
	String regex = null;
	String regexPure = null;
	String prefix = null;
	String suffix = null;

	int regexIndex = 0;
	int indexWithoutOccur = 0;
	protected StructImpl parent = null;

	/*
	 * Pattern pattern; Pattern patternPure;
	 */
	public StructImpl() {
	}

	public StructImpl(String name) {
		setName(name);
	}

	public StructImpl addChild(Struct child) {
		((StructImpl) child).parent = this;
		if (children == null) {
			children = new ArrayList<Struct>();
			childrenMap = new HashMap<String, Struct>();
		}
		children.add(child);
		childrenMap.put(child.getName(), child);
		return this;
	}

	public Struct getChild(String name) {
		return childrenMap.get(name);
	}

	public List<Struct> getChildren() {
		return children;
	}

	public int getMaxOccurrences() {
		return maxOccurrences;
	}

	public int getMinOccurrences() {
		return minOccurrences;
	}

	public String getName() {
		return name;
	}

	public String getRegularExpression() {
		return regex;
	}

	public String getRegularExpressionPure() {
		return regexPure;
	}

	public int getRegularExpressionIndex() {
		return regexIndex;
	}

	public int getRegularExpressionIndexWithoutOccur() {
		return indexWithoutOccur;
	}

	public StructImpl setMaxOccurrences(int occ) {
		this.maxOccurrences = occ;
		return this;

	}

	public StructImpl setMinOccurrences(int occ) {
		this.minOccurrences = occ;
		return this;

	}

	public StructImpl setName(String name) {
		this.name = name;
		return this;

	}

	public StructImpl setRegularExpression(String regex) {
		this.regex = regex;
		return this;

	}

	public StructImpl setRegularExpressionIndex(int regexIndex) {
		this.regexIndex = regexIndex;
		return this;

	}

	public StructImpl setRegularExpressionIndexWithoutOccur(
			int indexWithoutOccur) {
		this.indexWithoutOccur = indexWithoutOccur;
		return this;

	}

	StringBuffer handleOccur(StringBuffer res, CalcContext context,
			String delimiter) {
		if (delimiter != null) {
			res.insert(0, "(");
			res.append("(" + qDelimiter(delimiter) + "){0,1})");
			context.calcIndex++;
		}
		if (!(this.getMinOccurrences() == 1 && this.getMaxOccurrences() == 1)) {
			res.insert(0, "(");
			if (getParentDelimiter() != null && this.getMaxOccurrences() > 1) {
				res.insert(0, "(");
				res.append("(" + getParentDelimiter() + "){0,1})");
				context.calcIndex++;
			}
			res.append("{" + getMinOccurrences() + "," + getMaxOccurrences()
					+ "}");
			res.append(")");
		}

		return res;
	}

	private String qDelimiter(String delimiter) {
		int index = delimiter.indexOf("(?");
		if (index > 0) {
			return quote(delimiter.substring(0, index))
					+ delimiter.substring(index);
		} else {
			return quote(delimiter);
		}
	}

	void handleOccurIndex(CalcContext context, String delimiter) {
		if (delimiter != null) {
			context.calcIndex++;
		}
		if (!(this.getMinOccurrences() == 1 && this.getMaxOccurrences() == 1)) {
			context.calcIndex++;
			if (getParentDelimiter() != null && this.getMaxOccurrences() > 1) {

				context.calcIndex++;

			}

		}
	}

	public String calcRegex() {
		return calcRegex(new CalcContext(), null);
	}

	public String getParentDelimiter() {
		if (parent instanceof StructSequenceImpl) {
			return ((StructSequenceImpl) parent).getDelimiterRegex();
		}

		return null;
	}

	public String getPrefix() {
		return prefix;
	}

	public String getSuffix() {
		return suffix;
	}

	public StructImpl setPrefix(String pref) {
		if ("".equals(pref))
			pref = null;
		this.prefix = pref;
		return this;
	}

	public StructImpl setSuffix(String suff) {
		if ("".equals(suff))
			suff = null;
		this.suffix = suff;
		return this;
	}

	/*
	 * public synchronized void setPattern(Pattern pattern) { this.pattern =
	 * pattern; } public Pattern getPattern() { return pattern; }
	 * 
	 * public synchronized void setPatternPure(Pattern pattern) {
	 * this.patternPure = pattern; } public Pattern getPatternPure() { return
	 * patternPure; }
	 */

	public static String quote(String s) {
		int slashEIndex = s.indexOf("\\E");
		if (slashEIndex == -1)
			return "\\Q" + s + "\\E";

		StringBuilder sb = new StringBuilder(s.length() * 2);
		sb.append("\\Q");
		slashEIndex = 0;
		int current = 0;
		while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
			sb.append(s.substring(current, slashEIndex));
			current = slashEIndex + 2;
			sb.append("\\E\\\\E\\Q");
		}
		sb.append(s.substring(current, s.length()));
		sb.append("\\E");
		return sb.toString();
	}

}
